<?php
/**
-------------------------
GNU GPL COPYRIGHT NOTICES
-------------------------
This file is part of FlexicaCMS.

FlexicaCMS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

FlexicaCMS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with FlexicaCMS.  If not, see <http://www.gnu.org/licenses/>.*/

/**
 * $Id$
 *
 * @author FlexicaCMS team <contact@flexicacms.com>
 * @link http://www.flexicacms.com/
 * @copyright Copyright &copy; 2009-2010 Gia Han Online Solutions Ltd.
 * @license http://www.flexicacms.com/license.html
 */
  
Yii::import('Admin.components.DynamicForm',true);
class WidgetService extends FServiceBase
{
    /**
    * Get metadate for widget editor of a widget or widget instance
    * 
    * @param int id widget definition id
    * @param int instanceId widget instance id
    * @return FServiceModel
    */
    public function getEditor($params) 
    {
        $pageWidgetId = $this->getParam($params, 'page_widget_id', 0);
        $data = array();
        if ($pageWidgetId)
        {
            $model = PageWidget::model()->with(array('widgetData'=>array('with'=>'widget')))->findByPk($pageWidgetId);
            if (is_object($model))
            {
                $instance = $model->widgetData;
                eval("\$data = {$instance->data};");
                $widget = $instance->widget;
            }
        }
        else
        {
            $instance = WidgetData::model()->findByPk($this->getParam($params,'instanceId',0));
            if ($instance)
            {
                $widget = $instance->widget;
                eval("\$data = {$instance->data};");
            }
            else
            {
                $widget = WidgetDefinition::model()->findByPk($this->getParam($params,'id',0));
                $data = array();
            }
        }
        
        if (!$widget)
            return $this->result->fail(ERROR_INVALID_DATA,Yii::t('CmsModule.widget','Cannot build editor for an unknown widget ID.'));
            
        $result = $this->getForm(array('dtd' => $widget->dtd), $data);
        $config = array();
        $fields = array();
        
        //add isntance's widget_id hidden field
        $config['WidgetData[widget_id]'] = array(
            'type'=>'hidden',
        );
        $field = new DynamicFormAttribute();
        $field->name = 'WidgetData[widget_id]';
        $field->label = 'WidgetData[widget_id]';
        $field->value = $widget->id;
        $fields['WidgetData[widget_id]'] = $field;
        
        //add isntance's id hidden field
        if ($instance)
        {
            $config['WidgetData[id]'] = array(
                'type'=>'hidden',
            );
            $field = new DynamicFormAttribute();
            $field->name = 'WidgetData[id]';
            $field->label = 'WidgetData[id]';
            $field->value = (isset($instance)?$instance->id:0);
            $fields['WidgetData[id]'] = $field;
        }
        
        //add instance's name field
        $config['WidgetData[name]'] = array(
            'type'=>'text',
        );
        $field = new DynamicFormAttribute();
        $field->name = 'WidgetData[name]';
        $field->label = 'Name';
        $field->value = (isset($instance)?$instance->name:'');
        $fields['WidgetData[name]'] = $field;
        
        //get the fields list, we need to assign values into correspondent fields
        $fields = CMap::mergeArray($fields, $result->attributes);

        $this->result->processed('config', CMap::mergeArray($config, $result->config));
        $this->result->processed('attributes', $fields);
        
        return $this->result;
    }
    
    /**
    * Build the form configutation array based on a DTD of a widget
    * 
    * @param string $dtd
    */
    public function getForm($params, $data)
    {
        $dtd = $this->getParam($params, 'dtd','','tag,xss,newline');
        if (empty($dtd))
            return $this->result->fail(ERROR_INVALID_DATA,Yii::t('CmsModule.widget','Cannot cretae form configutation for an empty DTD.'));
        //create Dom document
        $doc = new DOMDocument();
        $doc->loadXML("<root>{$dtd}</root>");
        $doc = $doc->childNodes->item(0); //down one level as root is just a dummy node
        $elements = $doc->childNodes;
        
        $configuration = $this->getConfiguration($elements);
        $attributes = array();
        foreach($configuration as $fieldName => $conf)
        {
            if (strpos($fieldName,'WidgetData') === false)
            {   //multiple fieldset
                $group = $fieldName;
                $i = 0; $count = null;
                while (true)
                {
                    foreach(array_keys($conf) as $fieldName)
                    {
                        preg_match('/WidgetData\[(.*)]/',$fieldName,$matches);
                        $fieldId = $matches[1];
                        
                        if ($count == null) //find out how many field set we have in data
                            if (isset($data[$fieldId]))
                                $count = count($data[$fieldId]);
                            else
                                $count = 0;
                                
                        $attr = new DynamicFormAttribute();
                        $attr->name = $fieldName;
                        $attr->label = $this->getAttributeLabel($fieldName);
                        $attr->value = isset($data[$fieldId][$i])?$data[$fieldId][$i]:null;
                        $attributes["{$group} {$fieldName} {$i}"] = $attr;
                    }
                    $i++;
                    if ($i >= $count) break;
                }
            }
            else
            {
                preg_match('/WidgetData\[(.*)\]/',$fieldName,$matches);
                $fieldId = $matches[1];

                if (strpos($fieldId, '_htmlOptions'))
                {
                    $fieldId = str_replace('_htmlOptions', '', $fieldId);
                    $attributes[$fieldId] = $conf;
                }
                else
                {
                    $attr = new DynamicFormAttribute();
                    $attr->name = $fieldName;
                    $attr->label = $this->getAttributeLabel($fieldName);
                    $attr->value = isset($data[$fieldId])?$data[$fieldId]:null;
                    $attributes[$fieldName] = $attr;
                }
            }
        }
            
//        print_r($configuration);
//        foreach($attributes as $a)
//            echo $a->name,' = ',$a->value,"\n",
        
        $this->result->processed('config', $configuration);
        $this->result->processed('attributes', $attributes);
        return $this->result;
    }
    
    /**
    * Get form configuration for a set of nodes
    * 
    * @param DOMNodeList $elements
    */
    protected function getConfiguration($elements)
    {
        $conf = array();
        for($i=0; $i < $elements->length; $i++)
        {
            $node = $elements->item($i);
            if ($node->nodeName == 'multiple')
            {
                $group = $node->getAttribute('id');
                $conf[$group] = $this->getConfiguration($node->childNodes);
                continue;
            }
            
            if (count($node->attributes))
            {
                $fieldId = $node->getAttribute('id');
                $fieldName = "WidgetData[{$fieldId}]";
            
                if (!in_array($node->nodeName,array('text','html','js','css','date')))
                {   //HTML tag
                    $htmlOptions = array();
                    foreach($node->attributes as $attr)
                    {
                        if (strpos($attr->value,'input:') === 0)
                        {
                            $fieldName = "WidgetData[{$fieldId}_{$attr->name}]";
                            
                            $fieldDesc = $this->parseInput($attr->value);
                            $conf[$fieldName] = $fieldDesc;
                        }
                        else
                        {
                            $htmlOptions = array($attr->name=>$attr->value);
                        }
                    }
                    if ($node->nodeName == 'file')
                    {
                        $conf["WidgetData[{$fieldId}_file]"]['htmlOptions'] = $htmlOptions;
                    }
                }
                elseif (in_array($node->nodeName,array('js','css')))
                {
                    $script = $node->getAttribute('script');
                    if (strpos($script,'input:') !== 0) continue;
                    $fieldDesc = $this->parseInput($script);
                    $conf[$fieldName] = $fieldDesc;
                }
                else
                {   //text content (text, html, js,...)
                    $fieldDesc = $this->parseInput('input:'.$node->nodeName);
                    $conf[$fieldName] = $fieldDesc;
                }
            }            
        }
        return $conf;
    }
    
    protected function parseInput($str)
    {
        $default = null;
        if (strpos($str,'|') !== false)
            list($input,$default) = explode('|',$str);
        else
            $input = $str;
            
        $type = substr($input,6);
        return array(
            'type'=>$type,
            'default'=>$default
        );
    }
    
    protected function getAttributeLabel($fieldName)
    {
        $fieldName = substr($fieldName,11,strlen($fieldName)-12);
        $fieldName = ucwords(trim(strtolower(str_replace(array('-','_','.'),' ',preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $fieldName)))));
        
        return strtr($fieldName, array(
            ' Src' => ' Source',
            ' Alt' => ' Alternative Text',
            ' Img' => ' Image',
            ' Href' => ' URL',
        ));
    }
}